package com.learn.training.multithread.chapter6.minchapter7.demo2;

import java.util.concurrent.locks.StampedLock;

/**
 * 在一个共享的二维坐标点系统中，只有当点的坐标为原点 (0, 0) 时，才允许更新其坐标值。其他线程可以安全地读取坐标值。
 */
public class Point {
    private double x, y;
    private final StampedLock lock = new StampedLock();

    /**
     * 更新坐标
     * @param newX
     * @param newY
     */
    public void moveIfAtOrigin(double newX, double newY) {
        //获取悲观读锁
        long stamp = lock.readLock();
        try {
            // 检查条件是否满足
            if (x == 0.0 && y ==0.0){
                // 如果满足条件，尝试将读锁升级为写锁
                stamp = lock.tryConvertToWriteLock(stamp);
                if (stamp != 0L) {
                    // 升级成功，直接更新坐标
                    x = newX;
                    y = newY;
                }else{
                    // 升级失败，释放读锁并获取写锁
                    lock.unlockRead(stamp);// 释放读锁
                    stamp = lock.writeLock();// 获取写锁
                    x = newX;
                    y = newY;
                }
            }
        }finally {
            // 释放锁
            lock.unlock(stamp);
        }
    }

    // 获取坐标
    public double[] getXY(){
        // 获取读锁
        long stamp = lock.readLock();
        try {
            return new double[]{x, y};
        } finally {
            // 释放读锁
            lock.unlockRead(stamp);
        }
    }
}
